﻿#pragma once

#include <learn/math/line_search.h>

namespace xi
{

namespace math
{

/**
 * @brief 最速下降法
 *
 * @param[in] f
 * @param[in] df
 * @param[in] x
 * @param[in] tol
 * @return T
 */
template <class T> inline T steepest_descent(double (*f)(T), T (*df)(T), T x, double tol)
{
    T d = -df(x);
    while (d.norm() > tol)
    {
        double alpha = golden_section_line_search(f, x, d, tol);
        x += d * alpha;
        d = -df(x);
    }
    return x;
}

/**
 * @brief 纯牛顿法
 *
 * @tparam T
 * @tparam U
 * @param[in] f
 * @param[in] hf
 * @param[in] x
 * @param[in] tol
 * @return T
 */
template <class T, class U = T> inline T pure_newton(T (*df)(T), U (*hf)(T), T x, double tol)
{
    T g = df(x);
    while (g.norm() > tol)
    {
        x -= left_divide(hf(x), g);
        g = df(x);
    }
    return x;
}

/**
 * @brief 线搜索牛顿法
 *
 * @tparam T
 * @tparam U
 * @param[in] f
 * @param[in] df
 * @param[in] hf
 * @param[in] x
 * @param[in] tol
 * @return T
 */
template <class T, class U = T>
inline T line_search_newton(double (*f)(T), T (*df)(T), U (*hf)(T), T x, double tol)
{
    T g = df(x);
    while (g.norm() > tol)
    {
        auto d = left_divide(-hf(x), g);
        x += d * golden_section_line_search<T>(f, x, d, tol);
        g = df(x);
    }
    return x;
}

} // namespace math

} // namespace xi
